package com.pactera.miyuangroup.service.impl;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.pactera.miyuangroup.common.Constants;
import com.pactera.miyuangroup.common.RedisOperation;
import com.pactera.miyuangroup.config.CommonConfig;
import com.pactera.miyuangroup.db.entity.LoginUser;
import com.pactera.miyuangroup.db.entity.OrganizationStructure;
import com.pactera.miyuangroup.db.enums.ShowState;
import com.pactera.miyuangroup.db.mapper.LoginUserMapper;
import com.pactera.miyuangroup.service.LoginRoleService;
import com.pactera.miyuangroup.service.LoginUserService;
import com.pactera.miyuangroup.service.MiyuanDataService;
import com.pactera.miyuangroup.service.OrganizationStructureService;
import com.pactera.miyuangroup.util.IpUtils;
import com.pactera.miyuangroup.util.JwtUtils;
import com.pactera.miyuangroup.vo.convertor.LoginUserConvert;
import com.pactera.miyuangroup.vo.request.PageRequest;
import com.pactera.miyuangroup.vo.request.app.AppLoginPara;
import com.pactera.miyuangroup.vo.request.web.AddUserRequest;
import com.pactera.miyuangroup.vo.request.web.LoginPara;
import com.pactera.miyuangroup.vo.request.web.TransportReques;
import com.pactera.miyuangroup.vo.request.web.UpdateUserRequest;
import com.pactera.miyuangroup.vo.response.AccessToken;
import com.pactera.miyuangroup.vo.response.ResultModel;
import com.pactera.miyuangroup.vo.response.ResultStatusCode;
import com.pactera.miyuangroup.vo.response.User;
import com.pactera.miyuangroup.vo.response.miyuan.MiYuanModel;
import com.pactera.miyuangroup.vo.response.miyuan.MiYuanPage;
import com.pactera.miyuangroup.vo.response.miyuan.UserInfo;
import com.pactera.miyuangroup.vo.response.web.TransportRes;
import com.pactera.miyuangroup.vo.response.web.UserListRes;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;

import static java.util.Collections.emptyList;

/**
 * <p>
 * 用户信息表 服务实现类
 * </p>
 *
 * @author WangWu
 * @since 2018-04-17
 */
@Service
@Slf4j
public class LoginUserServiceImp extends ServiceImpl<LoginUserMapper, LoginUser> implements LoginUserService {
    @Autowired
    private LoginUserConvert loginUserConvert;
    @Autowired
    private OrganizationStructureService organizationStructureService;

    @Autowired
    private LoginRoleService loginRoleService;
    @Autowired
    private RedisOperation redis;
    @Autowired
    private BCryptPasswordEncoder bCryptPasswordEncoder;
    @Autowired
    private CommonConfig common;
    @Autowired
    private MiyuanDataService miyuanDataService;

    /**
     * 用户列表分页查询
     *
     * @param @return
     * @throws
     * @Description:
     * @date 2018年4月17日 上午11:25:32
     */
    @Override
    public Page<UserListRes> selectUserList(PageRequest pageRequest) {
        Page<UserListRes> page = new Page<UserListRes>(pageRequest.getCurrent(), pageRequest.getSize());
        try {
            page = page.setRecords(baseMapper.selectUserByList(page));
        } catch (Exception e) {
            log.info("分页查询用户列表异常");
            e.printStackTrace();
        }
        return page;
    }

    @Override
    public AccessToken loginWeb(LoginPara loginPara) {

        log.info("{}用户登录", loginPara.getUserName());
        AccessToken accessToken = new AccessToken();
        EntityWrapper<LoginUser> ew = new EntityWrapper<LoginUser>();
        ew.eq("user_name", loginPara.getUserName());
        ew.eq("app", Boolean.FALSE);//不是APP用户
        ew.eq("state", ShowState.ENABLE.getValue());//用户启用
        LoginUser loginUser = selectOne(ew);
        if (null == loginUser) {
            log.info("{}用户不存在", loginPara.getUserName());
            throw new UsernameNotFoundException("用户不存在");
        }
        if (!bCryptPasswordEncoder.matches(loginPara.getPassword(), loginUser.getUserPassword())) {
            log.info("{}用户密码不正确", loginPara.getUserName());
            throw new UsernameNotFoundException("用户密码不正确");
        }
        String key = UUID.randomUUID().toString();//key
        String token = JwtUtils.createToken(loginUser.getUserName(), loginUser.getId(), emptyList());
        redis.set(Constants.REDIS_AUTHORIZATION_TOKEN + key, JwtUtils.getAuthorizationTTLMillis(), token);
        log.info("token：{}", token);
        accessToken.setAccess_token(key);
        accessToken.setExpires_in(JwtUtils.getAuthorizationTTLMillis());
        loginUser.setLoginIp(loginPara.getIp());
        loginUser.setLoginTime(new Date());
        updateById(loginUser);
        return accessToken;
    }


    /**
     * 手机端登录
     *
     * @param loginPara
     * @return
     */
    @Override
    public ResultModel<AccessToken> loginApp(AppLoginPara loginPara) {

        String job = "CSAPP";
        log.info("{}用户登录", loginPara.getPhone());
        AccessToken accessToken = new AccessToken();
        EntityWrapper<LoginUser> ew = new EntityWrapper<LoginUser>();
        ew.eq("user_name", loginPara.getPhone());
        ew.eq("app", Boolean.TRUE);//是APP用户
        LoginUser loginUser = selectOne(ew);
        if (null == loginUser) {
            log.info("{}用户不存在", loginPara.getPhone());
            return ResultModel.fail(ResultStatusCode.USER_DOES_NOT_EXIST);
        }
        String code = redis.get(Constants.REDIS_SMS_CODE + loginPara.getPhone(), String.class, "-1");
        if (!code.equals(loginPara.getCode().toUpperCase()) && !job.equals(loginUser.getJobNumber())) {
            log.info("{}用户验证码不正确，验证码：{}", loginPara.getPhone(), loginPara.getCode());
            return ResultModel.fail(ResultStatusCode.INVALID_CAPTCHA);
        }
        String key = UUID.randomUUID().toString();//key
        String token = JwtUtils.createToken(loginUser.getUserName(), loginUser.getId(), common.getAppTokenEffectiveTime(), emptyList());
        redis.set(Constants.REDIS_AUTHORIZATION_TOKEN + key, common.getAppTokenEffectiveTime(), token);
        log.info("token：{}", token);
        accessToken.setAccess_token(key);
        accessToken.setExpires_in(JwtUtils.getAuthorizationTTLMillis());
        loginUser.setLoginIp(loginPara.getIp());
        loginUser.setLoginTime(new Date());
        updateById(loginUser);
        redis.delete(Constants.REDIS_SMS_CODE + loginPara.getPhone());
        return ResultModel.ok(accessToken);
    }


    /**
     * 发送短信验证码
     *
     * @param phone
     */
    @Override
    public String sendSmsCode(String phone) {
        String code = redis.get(Constants.REDIS_SMS_CODE + phone, String.class, "");
        if (StringUtils.isBlank(code)) {
            code = UUID.randomUUID().toString().replace("-", "");
            code = code.substring(code.length() - 6, code.length());
            log.info("短信验证码：{}", code);
            redis.set(Constants.REDIS_SMS_CODE + phone, common.getSms().getEffectiveTime(), code.toUpperCase());
        }
        return code.toLowerCase();
    }

    /**
     * 查询登录用户信息
     *
     * @param id
     * @return
     */
    @Override
    public User selectLoginInfoById(String id) {
        LoginUser loginUser = selectById(id);
        User user = loginUserConvert.convert2LoginUser(loginUser);
        return user;
    }

    /**
     * 验证用户名是否存在
     * 不区分 web APP
     *
     * @param userName
     * @return
     */
    @Override
    public boolean validateName(String userName) {
        EntityWrapper<LoginUser> ew = new EntityWrapper<LoginUser>();
        ew.eq("user_name", userName);
        ew.notIn("state", ShowState.DELETE.getValue());
        LoginUser loginUser = selectOne(ew);
        if (null == loginUser) {
            return false;
        }
        return true;
    }

    /**
     * 验证用户名是否存在
     * 区分web app
     * APP：true
     * Web：false
     *
     * @param userName 用户名
     * @param app      是否是APP用户
     * @return
     */
    @Override
    public boolean validateName(String userName, boolean app) {
        EntityWrapper<LoginUser> ew = new EntityWrapper<LoginUser>();
        ew.eq("user_name", userName);
        ew.eq("app", app);//不是APP用户
        ew.notIn("state", ShowState.DELETE.getValue());
        LoginUser loginUser = selectOne(ew);
        if (null == loginUser) {
            return false;
        }
        return true;
    }


    /**
     * web 端新增用户
     *
     * @param req
     * @param request
     * @return
     */
    @Override
    @Transactional
    public boolean AddUserByWeb(HttpServletRequest request, AddUserRequest req, String createrId) {
        //新增用户
        String pwd = bCryptPasswordEncoder.encode(req.getPassword());
        req.setPassword(pwd);
        LoginUser user = loginUserConvert.convert2AddUser(req);
        if (StringUtils.isBlank(user.getOrganizationId())) {
            user.setOrganizationId(Constants.SYS_ROOT);
        }
        user.setLoginTime(new Date());
        user.setLoginIp(IpUtils.getIpAddr(request));
        user.setApp(false);
        user.setCreater(createrId);
        user.setCreaterTime(new Date());
        user.setModifier(createrId);
        user.setModifierTime(new Date());
        user.setState(ShowState.ENABLE);
        boolean flg = insert(user);
        log.info("新增用户 ID:{} Name:{}", user.getId(), user.getUserName());
        flg = loginRoleService.updateUserRoles(user.getId(), req.getRoleId());
        return flg;
    }

    /**
     * web 端新增用户
     *
     * @param req
     * @param request
     * @return
     */
    @Override
    @Transactional
    public boolean UpdateUserByWeb(HttpServletRequest request, UpdateUserRequest req, String modifierId) {
        //新增用户
        if (StringUtils.isNotBlank(req.getPassword())) {
            String pwd = bCryptPasswordEncoder.encode(req.getPassword());
            req.setPassword(pwd);
        }
        LoginUser user = selectById(req.getId());
        if (null == user) {
            return false;
        }
        user = loginUserConvert.convert2AddUser(req, user);
        if (StringUtils.isBlank(user.getOrganizationId())) {
            user.setOrganizationId(Constants.SYS_ROOT);
        }
        user.setModifier(modifierId);
        user.setModifierTime(new Date());
        user.setState(ShowState.ENABLE);
        boolean flg = updateById(user);
        log.info("修改用户 ID:{} Name:{}", user.getId(), user.getUserName());
        flg = loginRoleService.updateUserRoles(user.getId(), req.getRoleId());
        return flg;
    }

    @Override
    public Page<TransportRes> selectTransportInfoList(TransportReques transportReques, String ordId) {
        //验证数据
        EntityWrapper wrapper = new EntityWrapper();
        //过滤无手机号码的员工
        wrapper.where("`user`.`phone` is not NULL");

        if (!Constants.SYS_ROOT.equals(ordId)) {
            wrapper.eq("organization_id", ordId);
        }
        if (StringUtils.isNotBlank(transportReques.getName())) {
            wrapper.like("`user`.`name`", transportReques.getName());
        }

        if (StringUtils.isNotBlank(transportReques.getJobNumber())) {
            wrapper.like("`user`.`job_number`", transportReques.getJobNumber());
        }

        if (StringUtils.isNotBlank(transportReques.getPhone())) {
            wrapper.eq("`user`.`phone`", transportReques.getPhone());
        }

       // wrapper.eq("`user`.`app`", true);

        //查询数据
        Page<TransportRes> transportResList = new Page<TransportRes>(transportReques.getCurrent(), transportReques.getSize());
        List<TransportRes> transportResListPO = baseMapper.selectTransportInfoList(transportResList, wrapper);


        transportResList.setRecords(transportResListPO);
        return transportResList;
    }


    /**
     * 用户信息同步
     *
     * @return
     */
    @Override
    public boolean syncMiyuanUserInfo() {
        //开始更新
        boolean flg = redis.get(Constants.REDIS_MIYUAN_USER_INFO_SYNC, Boolean.class, Boolean.TRUE);
        if (!flg) {
            return false;
        }
        //使用多线程
        miyuanDataService.executor.submit(new Runnable() {
            @Override
            public void run() {
                try {
                    redis.set(Constants.REDIS_MIYUAN_USER_INFO_SYNC, Boolean.FALSE);
                    miYuanUserInfo();
                    redis.set(Constants.REDIS_MIYUAN_USER_INFO_SYNC, Boolean.TRUE);
                } catch (Exception e) {
                    log.error("同步米源用户信息发生异常", e);
                    redis.set(Constants.REDIS_MIYUAN_USER_INFO_SYNC, Boolean.TRUE);
                }
            }
        });
        return true;
    }


    /**
     * @return
     */
    @Override
    public void syncMiyuanUserSchedulerInfo() {
        miYuanUserInfo();
    }

    /**
     * 同步米源数据
     */
    private void miYuanUserInfo() {
        int n = 1;
        MiYuanModel<MiYuanPage<UserInfo>> userInfos = miyuanDataService.getUserInfo(n, 100);
        while (true) {
            n++;
            //是否成功
            //失败，跳出，继续下一页
            if (!userInfos.isSuccess()) {
                continue;
            }

            //验证是否有数据，没有数据 跳出 继续下一页
            if (userInfos.getData() == null || userInfos.getData().getRecords() == null && userInfos.getData().getRecords().size() <= 0) {
                continue;
            }

            //更新用户集合
            List<LoginUser> upInfos = new ArrayList<>();
            //新增用户集合
            List<LoginUser> instInfos = new ArrayList<>();

            //循环数据入库
            for (UserInfo userInfo : userInfos.getData().getRecords()) {
                //查询数据库是否存在数据
                EntityWrapper<LoginUser> ew = new EntityWrapper<>();
                if (StringUtils.isNotBlank(userInfo.getJobNumber())) {
                    ew.eq("job_number", userInfo.getJobNumber());
                } else {
                    ew.eq("original_id", userInfo.getId());
                }

                ew.eq("app", Boolean.TRUE);
                LoginUser info = selectOne(ew);

                //查询机构数据库是否存在数据
                EntityWrapper<OrganizationStructure> orgEw = new EntityWrapper<>();
                orgEw.eq("original_id", userInfo.getOrganizationId());
                OrganizationStructure org = organizationStructureService.selectOne(orgEw);
                if (null != info) {
                    //存在，更新数据
                    info.setApp(Boolean.TRUE);
                    info.setOriginalId(userInfo.getId());
                    info.setJobNumber(userInfo.getJobNumber());
                    info.setModifier("-1");
                    info.setModifierTime(new Date());
                    info.setPhone(userInfo.getPhone());
                    info.setUserName(userInfo.getPhone());
                    info.setName(userInfo.getName());
                    info.setVehiclePhone(userInfo.getVehiclePhone());
                    if (null != org) {
                        info.setOrganizationId(org.getId());
                    }
                    upInfos.add(info);
                } else {
                    //不存在，新增数据
                    info = new LoginUser();
                    info.setApp(Boolean.TRUE);
                    info.setCreater("-1");
                    info.setCreaterTime(new Date());
                    info.setOriginalId(userInfo.getId());
                    info.setJobNumber(userInfo.getJobNumber());
                    info.setModifier("-1");
                    info.setModifierTime(new Date());
                    info.setPhone(userInfo.getPhone());
                    info.setUserName(userInfo.getPhone());
                    info.setName(userInfo.getName());
                    info.setVehiclePhone(userInfo.getVehiclePhone());
                    info.setState(ShowState.ENABLE);
                    if (null != org) {
                        info.setOrganizationId(org.getId());
                    }
                    instInfos.add(info);
                }
            }

            //更新
            if (upInfos.size() > 0) {
                updateBatchById(upInfos, upInfos.size());
            }
            //新增
            if (instInfos.size() > 0) {
                insertBatch(instInfos, instInfos.size());
            }

            //最后一页，退出
            if (userInfos.getData().isLast()) {
                break;
            }
            userInfos = miyuanDataService.getUserInfo(n, 100);
        }
    }
}
